/*
 * Copyright 2012 Biz-e (info@biz-e.nl)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.biz_e.android.calllog.util;

import android.os.AsyncTask;

/**
 * @author Joost A. Bloemsma
 *
 */
public class AsyncTaskRunner {
	private static final String DEBUG_TAG = AsyncTaskRunner.class.getSimpleName();
	private final AsyncCallbackTaskExecutor executor;
	private AsyncTaskRunnerListener listener = null;
	
	/**
	 * Constructs a new AsyncTaskRunner instance
	 * @param executor
	 */
	public AsyncTaskRunner(AsyncCallbackTaskExecutor executor) {
		super();
		this.executor = executor;
	}
	
	/**
	 * Executes the {@link AsyncCallbackTaskExecutor#executeAsync(AsyncTaskRunner)} method on a separate thread.
	 * @return The actual {@link AsyncTask}&lt;{@link AsyncCallbackTaskExecutor}, {@link Long}, {@link Integer}&gt; instance running the thread.
	 */
	public AsyncCallbackRunnerTask execute() {
		return this.execute(null);
	}
	
	/**
	 * Executes the {@link AsyncCallbackTaskExecutor#executeAsync(AsyncTaskRunner)} method on a separate thread.
	 * @param listener Will get notified of certain events before and after the execution.
	 * @return The actual {@link AsyncTask}&lt;{@link AsyncCallbackTaskExecutor}, {@link Long}, {@link Integer}&gt; instance running the thread.
	 */
	public AsyncCallbackRunnerTask execute(AsyncTaskRunnerListener listener) {
		this.listener = listener;
		return (AsyncCallbackRunnerTask)new AsyncCallbackRunnerTask(this).execute(executor);
	}
	
	/**
	 * @author Joost A. Bloemsma
	 *
	 */
	public interface AsyncCallbackTaskExecutor {
		/**
		 * The callback method being executed by the {@link AsyncTaskRunner}.
		 * @param runner Reference to the AsyncTaskRunner executing the callback
		 * @return a return value
		 */
		public int executeAsync(AsyncTaskRunner runner);
	}
	
	/**
	 * Defines a handler for all event methods of {@link AsyncTask}.<br/>
	 * This way it is possible to let those methods be handled somewhere else
	 * @author Joost A. Bloemsma
	 *
	 */
	public interface AsyncTaskRunnerListener {
		/**
		 * Runs on the UI thread before the {@link AsyncCallbackTaskExecutor#executeAsync(AsyncTaskRunner)} is 
		 * executed in the background.
		 * @param runner reference to the {@link AsyncTaskRunner} executing this method.
		 */
		public void onPreExecute(AsyncTaskRunner runner);
		
		/**
		 * <p>Runs on the UI thread after the {@link AsyncCallbackTaskExecutor#executeAsync(AsyncTaskRunner)} is 
		 * executed in the background. The specified result is the value returned by
		 * {@link AsyncCallbackTaskExecutor#executeAsync(AsyncTaskRunner)}.</p>
	     * 
	     * <p>This method won't be invoked if the task was cancelled.</p>
	     *
	     * @param runner reference to the {@link AsyncTaskRunner} executing this method.
	     * @param result The result of the operation computed by the callback method.
		 */
		public void onPostExecute(AsyncTaskRunner runner, Integer result);
		
		/**
		 * @param runner reference to the {@link AsyncTaskRunner} executing this method.
		 * @param result
		 */
		//public void onProgressUpdate(AsyncTaskRunner runner, Long... values);
		
		public void onCancelled(AsyncTaskRunner runner, Integer result);
		/**
		 * @param runner reference to the {@link AsyncTaskRunner} executing this method.
		 */
		public void onCancelled(AsyncTaskRunner runner);
	}
	
	private class AsyncCallbackRunnerTask extends AsyncTask<AsyncCallbackTaskExecutor, Long, Integer> {
		private final AsyncTaskRunner runner;
		private boolean listenerSet = false;
		
		private AsyncCallbackRunnerTask(AsyncTaskRunner runner) {
			super();
			this.runner = runner;
		}
		
		/**
		 * {@inheritDoc}
		 */
		@Override
		protected Integer doInBackground(AsyncCallbackTaskExecutor... params) {
			return params[1].executeAsync(runner);
		}
		
		/**
		 * {@inheritDoc}
		 */
		@Override
		protected void onPreExecute() {
			if(listenerSet) runner.listener.onPreExecute(runner);
		}
		
		/**
		 * {@inheritDoc}
		 */
		@Override
		protected void onPostExecute(Integer result) {
			if(listenerSet) runner.listener.onPostExecute(runner, result);
		}
		
//		/**
//		 * {@inheritDoc}
//		 */
//		@Override
//		protected void onProgressUpdate(Long... values) {
//			if(listenerSet) runner.listener.onProgressUpdate(runner, values);
//		}
		
		/**
		 * {@inheritDoc}
		 */
		@Override
		protected void onCancelled(Integer result) {
			if(listenerSet) runner.listener.onCancelled(runner, result);
		}
		
		/**
		 * {@inheritDoc}
		 */
		@Override
		protected void onCancelled() {
			if(listenerSet) runner.listener.onCancelled(runner);
		}
		
	}
}
